package utils

import (
	"bytes"
	"fmt"
	"github.com/xuri/excelize/v2"
)

type RowDataHatching func(row, col int, colTitle string) (value any, ok bool, err error)

type ExportExcelFile struct {
	// 保留默认的sheet
	ReserveSheets bool
	HeaderStyle   *excelize.Style
	BodyStyle     *excelize.Style
}

func NewExportExcelFile() *ExportExcelFile {
	ef := &ExportExcelFile{
		ReserveSheets: false,
	}
	ef.HeaderStyle = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"bbbbb9"}},
		Border: []excelize.Border{
			{Type: "left", Color: "000000", Style: 1},
			{Type: "right", Color: "000000", Style: 1},
			{Type: "top", Color: "000000", Style: 1},
			{Type: "bottom", Color: "000000", Style: 1},
		}}
	ef.BodyStyle = &excelize.Style{Border: []excelize.Border{
		{Type: "left", Color: "000000", Style: 1},
		{Type: "right", Color: "000000", Style: 1},
		{Type: "top", Color: "000000", Style: 1},
		{Type: "bottom", Color: "000000", Style: 1},
	}}
	return ef
}

func (ef *ExportExcelFile) Export(sheetName string, titles *[]string, rowDataHatching RowDataHatching) (*bytes.Buffer, error) {
	f, err := ef.initExcelFile(sheetName)
	if err != nil {
		return nil, err
	}
	defer func() {
		_ = f.Close()
	}()
	err = ef.exportExcelHeader(f, sheetName, titles)
	if err != nil {
		return nil, err
	}
	if rowDataHatching != nil {
		err = ef.exportExcelBody(f, sheetName, titles, rowDataHatching)
		if err != nil {
			return nil, err
		}
	}
	var buf bytes.Buffer
	if err := f.Write(&buf); err != nil {
		return nil, err
	}
	return &buf, nil
}

func (ef *ExportExcelFile) initExcelFile(sheetName string) (*excelize.File, error) {
	f := excelize.NewFile()
	_, err := f.NewSheet(sheetName)
	if err != nil {
		return nil, err
	}
	if !ef.ReserveSheets {
		for _, sheet := range f.GetSheetList() {
			if sheet != sheetName {
				_ = f.DeleteSheet(sheet)
			}
		}
	}
	return f, nil
}

func (ef *ExportExcelFile) exportExcelHeader(f *excelize.File, sheetName string, titles *[]string) error {
	for i, title := range *titles {
		colChar := rune(65 + i)
		err := f.SetCellValue(sheetName, fmt.Sprintf("%c%d", colChar, 1), title)
		if err != nil {
			return err
		}
	}
	// 设置表头样式
	if ef.HeaderStyle != nil {
		colChar := rune(65 + len(*titles) - 1)
		headerStyle, err := f.NewStyle(ef.HeaderStyle)
		if err != nil {
			return err
		}
		_ = f.SetCellStyle(sheetName, "A1", fmt.Sprintf("%c%d", colChar, 1), headerStyle)
	}
	return nil
}

func (ef *ExportExcelFile) exportExcelBody(f *excelize.File, sheetName string, titles *[]string, rowDataHatching RowDataHatching) error {
	row := 0
	breakRow := false
	var bodyStyle int
	var err error
	if ef.BodyStyle != nil {
		bodyStyle, err = f.NewStyle(ef.BodyStyle)
		if err != nil {
			return err
		}
	}
	for {
		for col, title := range *titles {
			value, ok, err := rowDataHatching(row, col, title)
			if err != nil {
				return err
			}
			if !ok {
				breakRow = true
				break
			}
			colChar := rune(65 + col)
			err = f.SetCellValue(sheetName, fmt.Sprintf("%c%d", colChar, row+2), value)
			if err != nil {
				return err
			}
		}
		if breakRow {
			break
		}
		if ef.BodyStyle != nil {
			colChar := rune(65 + len(*titles) - 1)
			_ = f.SetCellStyle(sheetName, fmt.Sprintf("%s%d", "A", row+2), fmt.Sprintf("%c%d", colChar, row+2), bodyStyle)
		}
		row++
	}
	return nil
}
